-- Operand Reader --

Parse.Operand .parser .op :-
	parse.expression .parser .op #

Parse.ExpressionNode .parser (ADDROF .mem) :- -- Address-of operator
	parser.scanner .parser .scanner,
	scan.match .scanner (SYM "&") !
	Parse.ExpressionNode .parser .mem #

Parse.ExpressionNode .parser (SIZE 1 .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "BYTE"),
	Parse.Pointer .parser .op ! #
Parse.ExpressionNode .parser (SIZE .size .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "WORD"),
	Parse.Pointer .parser .op,
	Config.WordSize .size ! #

Parse.ExpressionNode .parser (SIZE 1 .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "D8"), Parse.Pointer .parser .op ! #
Parse.ExpressionNode .parser (SIZE 2 .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "D16"), Parse.Pointer .parser .op ! #
Parse.ExpressionNode .parser (SIZE 4 .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "D32"), Parse.Pointer .parser .op ! #
Parse.ExpressionNode .parser (SIZE 8 .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID "D64"), Parse.Pointer .parser .op ! #
Parse.ExpressionNode .parser .op :- Parse.Pointer .parser .op ! #

Parse.ExpressionNode .parser (IMM .imm) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (NUM .imm) ! #

Parse.ExpressionNode .parser .op :-
	parser.scanner .parser .scanner,
	scan.match .scanner (ID .id), (
		Register .id .op;
		Label.Get .id .address, .op = (MEM $ $ 1 .address)
	) ! #

Parse.Pointer .parser (PTR .op) :-
	parser.scanner .parser .scanner,
	scan.match .scanner (SYM "["),
	parse.expression .parser .op,
	scan.match .scanner (SYM "]") ! #


-- Operands Reduction --

	-- Do the subtrees first
Simplify.OpTree (.op .p) (.out) :-
	Simplify.OpTree .p .p1,
	Simplify.Operand (.op .p1) .out ! #
Simplify.OpTree (.op .l .r) (.out) :-
	Simplify.OpTree .l .l1,
	Simplify.OpTree .r .r1,
	Simplify.Operand (.op .l1 .r1) .out ! #
Simplify.OpTree .op (.op1) :- Simplify.Operand .op .op1 ! #

	-- Casts
Simplify.Operand (SIZE .size1 (GR .size2 .r)) (GR .size2 .r) :-
	.size1 = .size2;
	Error "Cannot cast register to wrong size" # -- He's insane
Simplify.Operand (SIZE . .op) (.op) # -- No need anymore after check stage

	-- Evaluate constants if possible
Simplify.Operand (ADDop (IMM .i1) (IMM .i2))
	(IMM .imm) :- let .imm (.i1 + .i2) ! #
Simplify.Operand (SUBop (IMM .i1) (IMM .i2))
	(IMM .imm) :- let .imm (.i1 - .i2) ! #
Simplify.Operand (MULop (IMM .i1) (IMM .i2))
	(IMM .imm) :- let .imm (.i1 * .i2) ! #
Simplify.Operand (DIVop (IMM .i1) (IMM .i2))
	(IMM .imm) :- let .imm (.i1 / .i2) ! #
Simplify.Operand (NEGop (IMM .i1)) (IMM .imm) :- let .imm (0 - .i1) ! #

Simplify.Operand (ADDROF (PTR .o)) (.o) :- ! #
Simplify.Operand (PTR (ADDROF .o)) (.o) :- ! #

Simplify.Operand (ADDROF (MEM $ $ . .imm)) (IMM .imm) :- ! #
Simplify.Operand (PTR .p) (.mem) :- MemOp.Construct .p .mem ! #
Simplify.Operand .op (.op) :- ! #


-- Transform Pointers to Base/Index/Disp Format --

MemOp.Construct .op .mem :- MemOp.Convert .op .mem ! #
MemOp.Construct . (MEM $ $ 1 0) :-
	Error "Bad memory operand" #

MemOp.Convert (SIZE . .op) (.mem) :- MemOp.Convert .op .mem ! #
MemOp.Convert (ADDop .op1 .op2) (.mem) :-
	MemOp.Convert .op1 .mem1,
	MemOp.Convert .op2 .mem2,
	MemOp.Merge .mem1 .mem2 .mem ! #
MemOp.Convert (SUBop .op1 (IMM .negDisp)) (.mem) :-
	MemOp.Convert .op1 .mem1,
	let .disp (0 - .negDisp),
	MemOp.Merge .mem1 (MEM $ $ 1 .disp) .mem ! #
MemOp.Convert (GR .size .r) (MEM (GR .size .r) $ 1 0) :-
	Config.PointerSize .size ! #
MemOp.Convert (MULop (GR .size .r) (IMM .scale))
	(MEM $ (GR .size .r) .scale 0) :-
	Config.PointerSize .size ! #
MemOp.Convert (MULop (IMM .scale) (GR .size .r))
	(MEM $ (GR .size .r) .scale 0) :-
	Config.PointerSize .size ! #
MemOp.Convert (IMM .disp) (MEM $ $ 1 .disp) #

MemOp.Merge (MEM .base $ . .d1) (MEM .index $ . .d2)
	(MEM .base .index 1 .disp) :- let .disp (.d1 + .d2) ! #
MemOp.Merge (MEM .base $ . .d1) (MEM $ .index .scale .d2)
	(MEM .base .index .scale .disp) :- let .disp (.d1 + .d2) ! #
MemOp.Merge (MEM $ .index .scale .d1) (MEM .base $ . .d2)
	(MEM .base .index .scale .disp) :- let .disp (.d1 + .d2) #


-- Get Size --

Check.OperandSize (GR .size .) .size #
Check.OperandSize (IMM .) . #
Check.OperandSize (MEM . . . .) . #
Check.OperandSize (SIZE .size .) .size #
